---
title: 'Async actions'
sidebarTitle: 'Async actions'
description: 'How to run actions asynchronously with Nango'
---

## Synchronous or asynchronous execution

Both execution models have different trade-offs.

<table>
  <tr>
    <th>Execution mode</th>
    <th>Pros</th>
    <th>Cons</th>
    <th>Best fit for</th>
  </tr>
  <tr>
    <td><strong>Synchronous</strong></td>
    <td>
      <ul>
        <li>Immediate result</li>
        <li>Simple error handling</li>
        <li>Easier to debug</li>
      </ul>
    </td>
    <td>
      <ul>
        <li>You need to handle rate limits</li>
        <li>You need to handle concurrency</li>
      </ul>
    </td>
    <td>
      <ul>
        <li>Real-time user interactions</li>
        <li>Freshness of data is important (e.g., current settings)</li>
      </ul>
    </td>
  </tr>
  <tr>
    <td><strong>Asynchronous</strong></td>
    <td>
      <ul>
        <li>Handles rate limits and retries automatically</li>
        <li>Scales to large/batch workloads</li>
        <li>"Fire and forget" execution</li>
      </ul>
    </td>
    <td>
      <ul>
        <li>Result is not immediate</li>
        <li>Requires polling or webhook handling</li>
        <li>More complex error handling</li>
      </ul>
    </td>
    <td>
      <ul>
        <li>Bulk or bursty workloads</li>
        <li>Endpoints with very low rate limits</li>
        <li>Batch writes</li>
      </ul>
    </td>
  </tr>
</table>

## Executing action asynchronously

To trigger an action asynchronously, add the `X-Async` header or use the `triggerActionAsync` SDK method.

<Tabs>

<Tab title="cURL (standard endpoint)">

```bash
curl --request POST \
  --url https://api.nango.dev/action/trigger \
  --header 'Authorization: Bearer <ENV-SECRET-KEY>' \
  --header 'Connection-Id: <CONNECTION-ID>' \
  --header 'Provider-Config-Key: <INTEGRATION-ID>' \
  --header 'X-Async: true'
  --data '{
    "action_name": "<ACTION-NAME>",
    "input": { ... }
  }'
```
</Tab>

<Tab title="Node SDK">

```ts
import { Nango }  from '@nangohq/node';

const nango = new Nango({ secretKey: '<ENV-SECRET-KEY>' });

// Trigger an asynchronous action
const { id, statusUrl } = await nango.triggerActionAsync('<INTEGRATION-ID>', '<CONNECTION-ID>', '<ACTION-NAME>', jsonInput);

// Later, retrieve the result
try {
  const result = await nango.getAsyncActionResult({ id });
  ...
} catch (error) {
  // handle error
}
```
</Tab>

</Tabs>

You can also specify the maximum number of retries in case of failure using the `X-Max-Retries` header (the value must be between 0 and 5):

```bash
--header 'X-Max-Retries: 3'
```

<Warning>
When using retries with asynchronous actions, make sure your action logic is idempotent. This means that running the action multiple times with the same input should produce the same result without unwanted side effects.
</Warning>

### Response format

When triggering an action asynchronously, the response will include a status URL and ID that you can use to poll to obtain the action result:

```json
{
  "statusUrl": "/action/<ACTION-ID>",
  "id": "<ACTION-ID>"
}
```

### Checking the action result

Poll the action result endpoint to check if the action has completed:

<Tabs>

<Tab title="cURL">

```bash
curl --request GET \
  --url https://api.nango.dev/action/<ACTION-ID> \
  --header 'Authorization: Bearer <PROJECT-SECRET-KEY>'
```
</Tab>

<Tab title="Node SDK">

```ts
import { Nango }  from '@nangohq/node';

const nango = new Nango({ secretKey: '<PROJECT-SECRET-KEY>' });
const result = await nango.getAsyncActionResult({ id: '<ACTION-ID>' });
...
```
</Tab>

</Tabs>

<Note>
Execution timing for asynchronous actions is not guaranteed. Actions are currently processed sequentially per environment, so execution time depends on how many actions are triggered and how long each one runs. Design your implementation to handle potential delays.
</Note>

The behavior of the action result endpoint:

- Returns a `404` error if the action has not completed yet
- Returns a `200` with the actual result data once the action completes successfully
- Returns a `500` with an error once the action completes with a failure

### Receiving webhook notifications

Instead of polling, configure webhooks to be notified when an async action completes.
1. [Set up webhooks from Nango to your app](/implementation-guides/platform/webhooks-from-nango)
2. Enable the `Async action completed` webhook for your environment
3. When an action completes, Nango sends:

```json
{
  "type": "async_action",
  "from": "nango",
  "connectionId": "<CONNECTION-ID>",
  "providerConfigKey": "<INTEGRATION-ID>",
  "payload": {
    "id": "<ACTION-ID>",
    "statusUrl": "/action/<ACTION-ID>"
  }
}
```

The webhook's payload contains the same information as the initial response when triggering the action—an ID and status URL that you can use to retrieve the completed action result. After receiving this webhook, you can make a single API call to get the action result rather than repeatedly polling.

## Troubleshoot errors & monitor

Navigate to the **Logs** tab to inspect potential errors and monitor action executions.

<Tip>
**Questions, problems, feedback?** Please reach out in the [Slack community](https://nango.dev/slack).
</Tip>
